/**
***	@name PF.js 
*** @author shangshi 
*** @email fss123@gmail.com
*** @created 2011/06/20 
*** @updated 2011/07/01
**/

var pf,
	PF = pf = PF || {
	author: "shangshi", // 作者
	version: "1.1", // 版本	
	selector: { // 选择器
		/**
		*** @name selector 选择器
		*** @param {String} #id .className tagName
		*** @quote from James Padolsey
		*** @example 	
				$("#id")
				$(".className")
				$("div")
				$("#id > .className  div")
				$("#id1, #id2, .className1, .className2, div")
				$("#id", context)
		**/
		$: (function() {
			var snack = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig,
			exprClassName = /^(?:[\w\-_]+)?\.([\w\-_]+)/,
			exprId = /^(?:[\w\-_]+)?#([\w\-_]+)/,
			exprNodeName = /^([\w\*\-_]+)/,
			//辅助数组，是为了能像这样方便写代码：(part.match(exprClassName) || na)[1]
			na = [null,null];			
			function _find(selector, context) {
				//没有传入context的话 就默认为document
				context = context || document;
				//判断是不是只是选择id。这里看起来，只是选择id的话不能使用querySelectorAll？
				var simple = /^[\w\-_#]+$/.test(selector);
				if (!simple && context.querySelectorAll) {
					//如果DOM元素的querySelectorAll方法存在，立即用此方法查找DOM节点，并将结果转换为Array返回。
					//querySelectorAll是w3c制定的查询dom标准接口，目前四大个浏览器（firefox3.1 opera10, IE 8, safari 3.1+）都已经支持这个方法，使用浏览器原生支持的方法无疑可以很大地提高查询效率。
					return realArray(context.querySelectorAll(selector));
				}
				//如果querySelectorAll不存在，就要开始折腾了。
				//首先如果查询语句包含了逗号，就把用逗号分开的各段查询分离，调用本身_find查找各分段的结果，显然此时传入_find的查询字符串已经不包含逗号了
				//各分段查询结果用concat连接起来，返回时使用下面定义的unique函数确保没有重复DOM元素存在数组里。
				if (selector.indexOf(',') > -1) {
					var split = selector.split(/,/g), ret = [], sIndex = 0, len = split.length;
					for(; sIndex < len; ++sIndex) {
						ret = ret.concat( _find(split[sIndex], context) );
					}
					return unique(ret);
				}
				//如果不包含逗号，开始正式查询dom元素
				//此句把查询语句各个部分分离出来。snack正则表达式看不太懂，大致上就是把"#id div > p"变成数组["#s2", "b", ">", "p"]，空格和">"作为分隔符
				var parts = selector.match(snack),
					//取出数组里最后一个元素进行分析，由于mini库支持的查询方式有限，能确保在后面的片段一定是前面片段的子元素，例如"#a div"，div就是#a的子元素 "#a > p" p是#a的直接子元素
					//先把匹配最后一个查询片段的dom元素找出来，再进行父类过滤，就能找出满足整句查询语句的dom元素
					part = parts.pop(),
					//如果此片段符合正则表达式exprId，那就是一个ID，例如"#header"，如果是一个ID，则把ID名返回给变量id，否则返回null
					id = (part.match(exprId) || na)[1],
					//此句使用a = b && c 的方式，如果b为真，则返回c值赋给a；如果b为假，则直接返回b值给a。（null undefined false 0 "" 等均为假）
					//在这个框架里很多这样的用法。如果已经确定此片段类型是ID，就不必执行正则表达式测试它是不是class类型或者node类型了。直接返回null。
					//否则就测试它是不是class类型或者node类型，并把名字返回给变量className和nodeName。
					className = !id && (part.match(exprClassName) || na)[1],
					nodeName = !id && (part.match(exprNodeName) || na)[1],
					//collection是用来记录查询结果的
					collection;
				//如果此片段是class类型，如".red"，并且DOM的getElementsByClassName存在(目前Firefox3和Safari支持)，直接用此方法查询元素返回给collection
				if (className && !nodeName && context.getElementsByClassName) {
					collection = realArray(context.getElementsByClassName(className));
				} else {
					//**不明白这里为什么先查询nodeName再查询className再查询id，个人感觉把id提到前面来不是更能提高效率？
					//如果此片段是node类型，则通过getElementsByTagName(nodeName)返回相应的元素给collection。
					//如果此片段不是id和node，就会执行collection = realArray(context.getElementsByTagName('*'))，返回页面所有元素给collection，为筛选className做准备。
					collection = !id && realArray(context.getElementsByTagName(nodeName || '*'));
					//如果此片段是class类型，经过上面的步骤collection就储存了页面所有元素，把它传进下面定义的filterByAttr函数，找出符合class="className"的元素
					if (className) {
						collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)'));
					}
					//此处查询id，如果是id，就不需要考虑此片段的前面那些查询片段，例如"div #a"只需要直接返回id为a的元素就行了。
					//直接通过getElementById把它变成数组返回，如果找不到元素则返回空数组
					if (id) {
						var byId = context.getElementById(id);
						return byId?[byId]:[];
					}
				}
				//parts[0]存在，则表示还有父片段需要过滤，如果parts[0]不存在，则表示查询到此为止，返回查询结果collection就行了
				//collection[0]存在表示此子片段查询结果不为空。如果为空，不需要再进行查询，直接返回这个空数组。
				//还有父片段需要过滤，查询结果又不为空的话，执行filterParents过滤collection的元素，使之符合整个查询语句，并返回结果。
				return parts[0] && collection[0] ? filterParents(parts, collection) : collection;
			}			
			function realArray(c) {
				//把元素集合转换成数组
				try {
					//数组的slice方法不传参数的话就是一个快速克隆的方法
					//通过call让传进来的元素集合调用Array的slice方法，快速把它转换成一个数组并返回。
					return Array.prototype.slice.call(c);
				} catch(e) {
					//如果出错，就用原始方法把元素一个个复制给一个新数组并返回。
					//**什么时候会出错？
					var ret = [], i = 0, len = c.length;
					for (; i < len; ++i) {
						ret[i] = c[i];
					}
					return ret;
				}
			}			
			function filterParents(selectorParts, collection, direct) {
				//继续把最后一个查询片段取出来，跟_find里的part = parts.pop()一样
				var parentSelector = selectorParts.pop();
				//记得分离选择语句各个部分时，"#id div > p"会变成数组["#s2", "b", ">", "p"]，">"符号也包含在内。
				//如果此时parentSelector是">"，表示要查找的是直接父元素，继续调用filterParents，并把表示是否只查找直接父元素的标志direct设为true。
				if (parentSelector === '>') {
					return filterParents(selectorParts, collection, true);
				}
				//ret存储查询结果 跟_find()里的collection一样 r为ret的数组索引
				var ret = [],
					r = -1,
					//与_find()里的定义完全一样
					id = (parentSelector.match(exprId) || na)[1],
					className = !id && (parentSelector.match(exprClassName) || na)[1],
					nodeName = !id && (parentSelector.match(exprNodeName) || na)[1],
					//collection的数组索引
					cIndex = -1,
					node, parent,
					matches;
				//如果nodeName存在，把它转成小写字母以便比较
				nodeName = nodeName && nodeName.toLowerCase();
				//遍历collection每一个元素进行检查
				while ( (node = collection[++cIndex]) ) {
					//parent指向此元素的父节点
					parent = node.parentNode;
					do {
						//如果当前片段是node类型，nodeName是*的话无论如何都符合条件，否则应该让collection里元素的父元素的node名与之相等才符合条件
						matches = !nodeName || nodeName === '*' || nodeName === parent.nodeName.toLowerCase();
						//如果当前片段是id类型，就应该让collection里元素的父元素id与之相等才符合条件
						matches = matches && (!id || parent.id === id);
						//如果当前片段是class类型，就应该让collection里元素的父元素的className与之相等才符合条件
						//parent.className有可能前后包含有空格，所以用正则表达式匹配
						matches = matches && (!className || RegExp('(^|\\s)' + className + '(\\s|$)').test(parent.className));
						//如果direct=true 也就是说后面的符号是>，只需要查找直接父元素就行了，循环一次立刻break
						//另外如果找到了匹配元素，也跳出循环
						if (direct || matches) { break; }
					} while ( (parent = parent.parentNode) );
					//如果一直筛选不到，则一直循环直到根节点 parent=false跳出循环，此时matches=false
					//经过上面的检查，如果matches=true则表示此collection元素符合条件，添加到结果数组里。
					if (matches) {
						ret[++r] = node;
					}
				}
				//跟_find()一样，此时collection变成了ret，如果还有父片段，继续进行过滤，否则返回结果
				return selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret;
			}			
			var unique = (function(){
				//+new Date()返回时间戳作为唯一标识符
				//为了保存变量uid和方法data，使用了一个闭包环境
				var uid = +new Date();
				var data = (function(){
					//为了保存变量n，使用了一个闭包环境
					var n = 1;
					return function(elem) {
					//如果elem是第一次进来检验，cacheIndex=elem[uid]=false，赋给elem[uid]一个值并返回true
					//下次再进来检验时elem[uid]有了值，cacheIndex!=flase 就返回false
					//**此处不明白nextCacheIndex的作用，随便给elem[uid]一个值不就行了吗
						var cacheIndex = elem[uid],
							nextCacheIndex = n++;
						if(!cacheIndex) {
							elem[uid] = nextCacheIndex;
							return true;
						}
						return false;
					};
				})();
				return function(arr) {
					var length = arr.length,
						ret = [],
						r = -1,
						i = 0,
						item;
					//遍历每个元素传进data()增加标志，判断是否有重复元素，重复了就跳过，不重复就赋给ret数组
					for (; i < length; ++i) {
						item = arr[i];
						if (data(item)) {
							ret[++r] = item;
						}
					}
					//下次调用unique()时必须使用不同的uid
					uid += 1;
					//返回确保不会有重复元素的数组ret
					return ret;
				};
			})();			
			function filterByAttr(collection, attr, regex) {
				//通过属性名筛选元素
				var i = -1, node, r = -1, ret = [];
				//遍历collection里每一个元素
				while ( (node = collection[++i]) ) {
					//整个框架调用filterByAttr的只有这一句：collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)'));
					//筛选元素的className，如果符合，加进数组ret，否则跳过
					if (regex.test(node[attr])) {
						ret[++r] = node;
					}
				}
				//返回筛选结果
				return ret;
			}
			//返回_find，暴露给外部的唯一接口
			return _find;
		})(),
		/**
		*** @name $I 选择器
		*** @param {String} #id
		*** @example 
				$I("#id")
		*** @说明 返回符合id=#id的dom节点
		**/
		$I: function(id, context) {
			return PF.selector.$(id, context)[0];
		},
		/**
		*** @name $T 选择器
		*** @param {String} tagName
		*** @example 
				$T("tagName")
		*** @说明 返回符合tag=#tagName的dom节点
		**/
		$T: function(tagName, context) {
			return PF.selector.$(tagName, context);
		},
		/**
		*** @name $N 选择器
		*** @param {String} name
		*** @example 
				$N("name")
		*** @说明 返回符合name=name的dom节点
		**/
		$N: function(name) {
			return "[object String]" == Object.prototype.toString.call(name) ? document.getElementsByName(name) : name;
		},
		/**
		*** @name $C 选择器
		*** @param {String} className, {Object} context
		*** @example 
				$C(".className", context)
		*** @说明 
				返回符合context下class=.className的dom节点
				context 为上下文，即在context指定的上下文寻找对象
		**/
		$C: function(className, context) {
			return PF.selector.$(className, context);
		}	
	},
	/**
	*** @name each 遍历
	*** @param {Object[, Array]} source 源, {Function} iterator 迭代器
	*** @说明
			对源对象（数组）中的每个成员都通过iterator调用一遍
			iterator函数有两个参数，第一个为元素，第二个为索引，function(item, index)
	**/
	each: function(source, iterator) {
		if (typeof iterator == "function") {
			for (var i = 0, j = source.length; i < j; i++) {
				iterator.call(source, source[i], i);
			}
		}
	},
	/**
	*** @name extend 扩展
	*** @param {Object} desination 目标, {Object} source 源
	*** @说明
			将源对象的属性/方法扩展到目标对象中
	**/
	extend: function(destination, source) {
		for (var property in source) {
			destination[property] = source[property];
		}
		return destination;
	},
	string: { // 字符串
		/**
		*** @name isString
		*** @param {String} source 源
		*** @说明
				判断是否为string类型或String对象
		**/
		isString: function(source) {
			return "[object String]" == Object.prototype.toString.call(source);
		},
		/**
		*** @name trimStart
		*** @param {String} source 源
		*** @说明
				去掉字符串起始空白
		**/
		trimStart: function(source) {
			return source.replace(/^\s+/g, "");
		},
		/**
		*** @name trimEnd
		*** @param {String} source 源
		*** @说明
				去掉字符串结尾空白
		**/
		trimEnd: function(source) {
			return source.replace(/\s+$/g, "");
		},
		/**
		*** @name trim
		*** @param {String} source 源
		*** @说明
				去掉字符串两端空白
		**/
		trim: function(source) {
			return this.trimEnd(this.trimStart(source));
		},
		/**
		*** @name blank
		*** @param {String} source 源
		*** @说明
				将多余空白保留一个
		**/
		blank: function(source) {
			return source.replace(/\s+/g, " ");
		},
		/**
		*** @name camel 驼峰式字符串
		*** @param {String} source 源
		*** @说明
				一般用于将样式表内的属性字符串（如：z-index）转化成驼峰式（如：zIndex）
		**/
		camel: function(source) {
			if (source.indexOf("-") < 0 && source.indexOf("_") < 0) {
				return source;
			}
			return source.replace(/[-_][^-_]/g, function(match) {
				return match.charAt(1).toUpperCase();
			})
		},
		/**
		*** @name startsWith 
		*** @param {String} starts 开始字符, {String} source 源
		*** @说明
				返回判断是否以starts开始
				区分大小写
		**/
		startsWith: function(starts, source) {
			return new RegExp("^"+ starts, "g").test(source);
		},
		/**
		*** @name endsWith 
		*** @param {String} ends 开始字符, {String} source 源
		*** @说明
				返回判断是否以ends结束
				区分大小写
		**/
		endsWith: function(ends, source) {	
			return new RegExp(ends + "$", "g").test(source);
		},
		/**
		*** @name format 格式化字符串 
		*** @param {String} source 源
		*** @example
				var text = "I love {0}, and You love {1}, where are {0}!";
				format(text, "you", "me");
		*** @说明
				格式化字符串
		**/
		format: function(source) {
			var args = arguments; // 此处需要把format的arguments对象赋给一个变量
			return source.replace(/\{(\d+)\}/g, function (m, i) {
				return args[(i*1)+1];	// 此处调用的是format的arguments
			});
		},
		/**
		*** @name byteLength 
		*** @param {String} source 源
		*** @说明
				按字节获取字符串长度
		**/
		byteLength: function(source) {
			return source.replace(/[^\x00-\xff]/g, "--").length;
		},
		/**
		*** @name onlyDigit 
		*** @param {String} source 源
		*** @说明
				过滤字符串，只保留数字
		**/
		onlyDigit: function(source) {
			return source.replace(/[^\d]/g, "");
		},
		/**
		*** @name onlyChinese 
		*** @param {String} source 源
		*** @说明
				过滤字符串，只保留中文
		**/
		onlyChinese: function(source) {
			return source.replace(/[^\u4e00-\u9fa5\uf900-\ufa2d]/g, "");
		},
		/**
		*** @name onlyEnglish 
		*** @param {String} source 源
		*** @说明
				过滤字符串，只保留英文
		**/
		onlyEnglish: function(source) {
			return source.replace(/[^a-zA-Z]/g, "");
		},
		/**
		*** @name intercept 
		*** @param {String} source 源, {int} m 开始位置, {int} n 结束位置
		*** @说明
				截取从m开始到n之前的字符串片段，新字符串
		**/
		intercept: function(source, m, n) {
			return source.slice(m, n);
		},
		/**
		*** @name left 
		*** @param {String} source 源
		*** @说明
				截取从0到n之前的字符串，新字符串
		**/
		left: function(source, n) {
			return this.intercept(source, 0, n);
		},
		/**
		*** @name right 
		*** @param {String} source 源
		*** @说明
				截取从0到n之前的字符串，新字符串
		**/
		right: function(source, n) {
			return this.intercept(source, source.length - n);
		}
	},
	math:  { // 数学
		/**
		*** @name randomNumber 
		*** @param {int} start 开始, {int} end 结束
		*** @说明
				随机数生成器
		**/
		random: function(start, end) {
			if (!isNaN(start) && !isNaN(end) && start > 0 || end > 0){
				var _start = Math.ceil(Math.min(start, end)),
					_end = Math.floor(Math.max(start, end));
				_start = _start > 0 ? _start : 0;
				return Math.round(_start + Math.random() * (_end - _start));
			}	
		},
		/**
		*** @name uniqueId 
		*** @param none
		*** @说明
				唯一id生成器
		**/
		uniqueId: function() {
			return parseInt(Math.random() * 10000).toString() + (new Date()).getTime().toString();
		}	
	},
	array: { // 数组
		/**
		*** @name isArray 
		*** @param {Any} source 源
		*** @说明
				判断源是否为一个数组，返回布尔
		**/
		isArray: function(source) {
				return source && typeof source === "object" && typeof source.length === "number" && typeof source.splice === "function";
		},
		/**
		*** @name empty 
		*** @param {Array} source 源
		*** @说明
				清空一个数组
		**/
		empty: function(source) {
			source.length = 0;
		},
		/**
		*** @name removeAt 
		*** @param {Array} source 源, {int} index 索引
		*** @说明
				按指定索引删除元素
		**/
		removeAt: function(source, index) {
			return source.splice(index, 1)[0];
		},
		/**
		*** @name remove 
		*** @param {Array} source 源, {Any} match 删除元素
		*** @说明
				删除指定元素
		**/
		remove: function(source, match) {
			var length = source.length;
			while (length--) {
				if (length in source && source[length] === match) {
					source.splice(length, 1);
				}
			}
			return source;
		},
		/**
		*** @name indexOf 
		*** @param {Array} source 源, {Any} match 查询, {int} index 开始索引
		*** @说明
				查询数组中指定元素的索引位置
		**/
		indexOf: function(source, match, index) {
			var length = source.length;
			index = index || 0;
			if (index < 0) {
				index = Math.max(0, length + index);
			}
			for (; index < length; index++) {
				if (index in source && source[index] === match) {
					return index;
				}
			}
			return -1;
		},
		/**
		*** @name lastIndexOf 
		*** @param {Array} source 源, {Any} match 查询, {int} index 开始索引
		*** @说明
				从后往前，查询数组中指定元素的索引位置
		**/
		lastIndexOf: function(source, match, index) {
			var length = source.length;
			index = index || 0;
			if (!index || index >= length) {
				index = length - 1;
			}
			if (index < 0) {
				index += length;
			}
			for (; index >= 0; index--) {
				if (index in source && source[index] === match) {
					return index;
				}
			}
			return -1;
		},
		/**
		*** @name contains 
		*** @param {Array} source 源, {Any} match 查询
		*** @说明
				判断一个数组中是否包含指定元素
		**/
		contains: function(source, match) {
			return (this.indexOf(source, match) >= 0);
		},
		/**
		*** @name every 
		*** @param {Array} source 源, {Function} iterator 迭代器, {Obejct} context 函数调用时的this指针，默认是遍历数组
		*** @说明
				判断一个数组中是否所有元素都满足给定条件
		**/
		every: function(source, iterator, context) {
			for (var i = 0, j = source.length; i < j; i++) {
				if (i in source && !iterator.call(context || source, source[i], i)) {
					return false;
				}
			}
			return true;
		},
		/**
		*** @name some 
		*** @param {Array} source 源, {Function} iterator 迭代器, {Obejct} context 函数调用时的this指针，默认是遍历数组
		*** @说明
				判断一个数组中是否有部分元素满足给定条件
		**/
		some: function(source, iterator, context) {
			for (var i = 0, j = source.length; i < j; i++) {
				if (i in source && iterator.call(context || source, source[i], i)) {
					return true;
				}
			}
			return false;
		},
		/**
		*** @name filter 
		*** @param {Array} source 源, {Function} iterator 迭代器, {Obejct} context 函数调用时的this指针，默认是遍历数组
		*** @说明
				从数组中筛选符合条件的元素
		**/
		filter: function(source, iterator, context) {
			var temp = [],
				index = 0;
			if (typeof iterator == "function") {
				for (var i = 0, j = source.length; i < j; i++) {
					if (iterator.call(context || source, source[i], i)) {
						temp[index++] = source[i];
					}
				}
			}
			return temp;
		},
		/**
		*** @name find 
		*** @param {Array} source 源, {Function} iterator 迭代器
		*** @说明
				从数组中查找符合条件的第一个元素
		**/
		find: function(source, iterator) {
			if (typeof iterator == "function") {
				for (var i = 0, j = source.length; i < j; i++) {
					if (iterator.call(source, source[i], i)) {
						return source[i];
					}
				}
			}
			return null;
		},
		/**
		*** @name map 
		*** @param {Array} source 源, {Function} iterator 迭代器, {Obejct} context 函数调用时的this指针，默认是遍历数组
		*** @说明
				遍历所有元素，将每个元素应用方法进行转换，并返回转换后的新数组
		**/
		map: function(source, iterator, context) {
			var temp = [];
			for (var i = 0, j = source.length; i < j; i++) {
				temp[i] = iterator.call(context || source, source[i], i);
			}
			return temp;
		},
		/**
		*** @name hash 
		*** @param {Array} keys 源, {Array} values 源
		*** @说明
				将两个数组元素合并成一个类似hashMap结构的对象
				使用第一个数组作为key，第二个数组作为value
		**/
		hash: function(keys, values) {
			var temp = {},
				value = values && values.length;
			for (var i = 0, j = keys.length; i < j; i++) {
				temp[keys[i]] = (value && value > i) ? values[i] : true;
			}
			return temp;
		}
	},
	json: { // Json
		/**
		*** @name parse 
		*** @param {String} data
		*** @说明
				将字符串解析成json对象
		**/
		parse: function(data) {
			return (new Function("return (" + data + ")"))();
		},
		/**
		*** @name stringify 
		*** @param {json} data
		*** @说明
				将json对象解析成字符串
		**/
		stringify: (function() {
			/**
			 * 字符串处理时需要转义的字符表
			 * @private
			 */
			var escapeMap = {
				"\b": '\\b',
				"\t": '\\t',
				"\n": '\\n',
				"\f": '\\f',
				"\r": '\\r',
				'"' : '\\"',
				"\\": '\\\\'
			};			
			/**
			 * 字符串序列化
			 * @private
			 */
			function encodeString(source) {
				if (/["\\\x00-\x1f]/.test(source)) {
					source = source.replace(
						/["\\\x00-\x1f]/g, 
						function (match) {
							var c = escapeMap[match];
							if (c) {
								return c;
							}
							c = match.charCodeAt();
							return "\\u00" 
									+ Math.floor(c / 16).toString(16) 
									+ (c % 16).toString(16);
						});
				}
				return '"' + source + '"';
			}			
			/**
			 * 数组序列化
			 * @private
			 */
			function encodeArray(source) {
				var result = ["["], 
					l = source.length,
					preComma, i, item;
					
				for (i = 0; i < l; i++) {
					item = source[i];
					
					switch (typeof item) {
					case "undefined":
					case "function":
					case "unknown":
						break;
					default:
						if(preComma) {
							result.push(',');
						}
						result.push(baidu.json.stringify(item));
						preComma = 1;
					}
				}
				result.push("]");
				return result.join("");
			}			
			/**
			 * 处理日期序列化时的补零
			 * @private
			 */
			function pad(source) {
				return source < 10 ? '0' + source : source;
			}			
			/**
			 * 日期序列化
			 * @private
			 */
			function encodeDate(source){
				return '"' + source.getFullYear() + "-" 
						+ pad(source.getMonth() + 1) + "-" 
						+ pad(source.getDate()) + "T" 
						+ pad(source.getHours()) + ":" 
						+ pad(source.getMinutes()) + ":" 
						+ pad(source.getSeconds()) + '"';
			}			
			return function (value) {
				switch (typeof value) {
				case 'undefined':
					return 'undefined';					
				case 'number':
					return isFinite(value) ? String(value) : "null";					
				case 'string':
					return encodeString(value);					
				case 'boolean':
					return String(value);					
				default:
					if (value === null) {
						return 'null';
					} else if (value instanceof Array) {
						return encodeArray(value);
					} else if (value instanceof Date) {
						return encodeDate(value);
					} else {
						var result = ['{'],
							encode = baidu.json.stringify,
							preComma,
							item;							
						for (var key in value) {
							if (Object.prototype.hasOwnProperty.call(value, key)) {
								item = value[key];
								switch (typeof item) {
								case 'undefined':
								case 'unknown':
								case 'function':
									break;
								default:
									if (preComma) {
										result.push(',');
									}
									preComma = 1;
									result.push(encode(key) + ':' + encode(item));
								}
							}
						}
						result.push('}');
						return result.join('');
					}
				}
			};
		})()
	},
	browser: { // 浏览器
		chrome: (function() {
			if (/chrome\/(\d+\.\d)/i.test(navigator.userAgent)) {
				return + RegExp["\x241"];
			}
			return null;
		})(),
		firefox: (function() {
			if (/firefox\/(\d+\.\d)/i.test(navigator.userAgent)) {
				return + RegExp["\x241"];
			}
			return null;
		})(),
		safari: (function() {
			if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent)) {
				return + (RegExp["\x241"] || RegExp["\x242"]);
			}
			return null;
		})(),
		opera: (function() {
			if (/opera\/(\d+\.\d)/i.test(navigator.userAgent)) {
				return + RegExp["\x241"];
			}
			return null;
		})(),
		ie: (function() {
			if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
				return document.documentMode || + RegExp["\x241"];
			}
			return null;
		})(),
		maxthon: (function() {
			try {
				if (/(\d+\.\d)/.test(external.max_version)) {
					return + RegExp["\x241"];
				}
			} catch (e) {}
			return null;
		})(),
		isGecko: (function() {
			return (/gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent));
		})(),
		isWebkit: (function() {
			return /webkit/i.test(navigator.userAgent);
		})(),
		isStrict: (function() {
			return document.compatMode == "CSS1Compat";
		})()
	},
	event: { // 事件
		/**
		*** @name addHandler
		***	@param {Object} element DOM对象, {String} type 事件类型, {Function} handler 处理函数
		*** @说明
				事件监听
		**/
		addHandler: function(element, type, handler) {
			if (element.addEventListener) {
				element.addEventListener(type.replace(/^\s+|\s+$/g, ""), handler, false);
			} else if (element.attachEvent) {
				element.attachEvent("on" + type.replace(/^\s+|\s+$/g, ""), handler);
			} else {
				element["on" + type.replace(/^\s+|\s+$/g, "")] = handler;
			}
		},
		/**
		*** @name addHandlers
		***	@param {Object} element DOM对象, {String} types 事件类型, {Function} handler 处理函数
		*** @说明
				对多种事件进行监听
		**/
		addHandlers: function(element, types, handler) {
			types = types.split(",");
			if (types.length == 1) {
				PF.event.addHandler(element, types[0], handler);
			} else if (types.length > 1) {
				for (var i = 0, j = types.length; i < j; i++) {
					PF.event.addHandler(element, types[i], handler);
				}
			}
		},
		/**
		*** @name removeHandler
		***	@param {Object} element DOM对象, {String} type 事件类型, {Function} handler 处理函数
		*** @说明
				移除事件监听
		**/
		removeHandler: function(element, type, handler) {
			if (element.removeEventListener) {
				element.removeEventListener(type.replace(/^\s+|\s+$/g, ""), handler, false);
			} else if (element.detachEvent) {
				element.detachEvent("on" + type.replace(/^\s+|\s+$/g, ""), handler);
			} else {
				element["on" + type.replace(/^\s+|\s+$/g, "")] = null;
			}
		},
		/**
		*** @name getEvent
		***	@param event
		**/
		getEvent: function(event) {
			return event ||  window.event;
		},
		/**
		*** @name getTarget
		***	@param event
		*** @说明
				触发事件的对象
		**/
		getTarget: function(event) {
			event = this.getEvent(event);
			return event.target || event.srcElement;
		},
		/**
		*** @name preventDefault
		***	@param event
		*** @说明
				取消默认事件
		**/
		preventDefault: function(event) {
			event = this.getEvent(event);
			if (event.preventDefault) {
				event.preventDefault();
			} else {
				event.returnValue = false;
			}
		},
		/**
		*** @name stopPropagation
		***	@param event
		*** @说明
				禁止事件冒泡
		**/
		stopPropagation: function(event) {
			event = this.getEvent(event);
			if (event.stopPropagation) {
				event.stopPropagation();
			} else {
				event.cancelBubble = true;
			}
		},
		/**
		*** @name getKeyCode
		***	@param event
		*** @说明
				获取触发事件的键码
		**/
		getKeyCode: function(event) {
			event = this.getEvent(event);
			return event.keyCode;
		},
		/**
		*** @name isEnter
		***	@param event
		*** @说明
				判断是否敲击了回车键
		**/
		isEnter: function(event) {
			return this.getKeyCode(event) == 13;
		}
	},
	bom: { // bom
		/**
		*** @name getScrollTop
		*** @说明
				滚动条顶部位置
		**/
		getScrollTop: function() {
			return document.documentElement.scrollTop || document.body.scrollTop;
		},
		/**
		*** @name getClientHeight
		*** @说明
				视窗高度
		**/
		getClientHeight: function() {
			return Math.max(document.documentElement.clientHeight, document.body.clientHeight);
		},
		/**
		*** @name getScrollHeight
		*** @说明
				文档实际高度
		**/
		getScrollHeight: function() {
			return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
		},
		/**
		*** @name isPageBottom
		*** @说明
				滚动条是否触底
		**/
		isPageBottom: function() {
			return (this.getScrollTop() + this.getClientHeight()) == this.getScrollHeight();
		}
	},
	dom: { // dom
		/**
		*** @name _NAME_ATTRS
		*** @说明
				提供给setAttr与getAttr方法作名称转换使用
		**/
		_NAME_ATTRS: function() {
			var temp = {
				"cellpadding" : "cellPading",
				"cellspacing" : "cellSpacing",
				"colspan": "colSpan",
				"rowspan": "rowSpan",
				"valign": "vAlign",
				"usemap": "useMap",
				"frameborder": "frameBorder"
			};
			if (PF.browser.ie < 8) {
				temp["for"] = "htmlFor";
				temp["class"] = "className";
			} else {
				temp["htmlFor"] = "for";
				temp["className"] = "class";
			}
			return temp;			
		},
		/**
		*** @name setAttr
		***	@param {Object} element 节点对象, {String} key 键名, {String} value 键值
		*** @说明
				设置节点属性
		**/
		setAttr: function(element, key, value) {
			if (key == "style") {
				element.style.cssText = value;
			} else {
				key = PF.dom._NAME_ATTRS[key] || key;
				element.setAttribute(key, value);
			}
		},
		/**
		*** @name setAttrs
		***	@param {Object} element 节点对象, {Object} attributes 属性名值对
		*** @说明
				批量设置节点属性
		**/
		setAttrs: function(element, attributes) {
			for (var key in attributes) {
				this.setAttr(element, key, attributes[key]);
			}
			return element;
		},
		/**
		*** @name getAttr
		***	@param {Object} element 节点对象, {String} key 键名
		*** @说明
				设置节点属性
		**/
		getAttr: function(element, key) {
			if (key == "style") {
				return element.style.cssText;
			}
			key = this._NAME_ATTRS[key] || key;
			return element.getAttribute(key);
		},
		/**
		*** @name create
		***	@param {String} tagName 标签名, {Object} attributes 属性名值对
		*** @说明
				创建节点
		**/
		create: function(tagName, attributes) {
			var element = document.createElement(tagName),
				attributes = attributes || {};
			return PF.dom.setAttrs(element, attributes);
		},
		/**
		*** @name getDocument
		***	@param {Object} element 节点对象
		*** @说明
				获取目标节点所属的document对象
		**/
		getDocument: function(element) {
			return element.nodeType == 9 ? element : element.ownerDocument || element.doucment;
		},
		/**
		*** @name getParent
		***	@param {Object} element 节点对象
		*** @说明
				获取目标节点所属的父节点
		**/
		getParent: function(element) {
			return element.parentElement || element.parentNode || null;
		},
		/**
		*** @name insertBefore
		***	@param {Object} newElement 新节点, {Object} existElement 存在节点
		*** @说明
				在指定节点之前插入节点
		**/
		insertBefore: function(newElement, existElement) {
			var parent = PF.dom.getParent(existElement);
			if (parent) {
				parent.insertBefore(newElement, existElement);
			}
			return newElement;
		},
		/**
		*** @name insertAfter
		***	@param {Object} newElement 新节点, {Object} existElement 存在节点
		*** @说明
				在指定节点之后插入节点
		**/
		insertAfter: function(newElement, existElement) {
			PF.dom.insertBefore(newElement, existElement.nextSibling);
			return newElement;
		},
		/**
		*** @name getParent
		***	@param {Object} element 节点对象
		*** @说明
				获取目标节点的文本内容
		**/
		getText: function(element) {
			var temp = "",
				childs;
			if (element.nodeType === 3 || element.nodeType === 4) {
				temp += element.nodeValue;
			} else if (element.nodeType !== 8) {
				for (var i = 0, j = element.childNodes.length; i < j; i++) {
					temp += this.getText(element.childNodes[i]);
				}
			}
			return temp;
		},
		/**
		*** @name remove
		***	@param {Object} element 节点对象
		*** @说明
				删除目标节点
		**/
		remove: function(element) {
			element.parentNode && element.parentNode.removeChild(element);
		},
		/**
		*** @name children
		***	@param {Object} element 节点对象
		*** @说明
				获取目标节点的直接子节点
		**/
		children: function(element) {
			for (var children = [], temp = element.firstChild; temp; temp = temp.nextSibling) {
				if (temp.nodeType == 1) {
					children.push(temp);
				}
			}
			return children;
		},
		/**
		*** @name addClass
		***	@param {Object} element 节点对象, {String} className 类名
		*** @说明
				增加目标节点的class
		**/
		addClass: function(element, className) {
			var classArray = className.split(/\s+/),
				temp = element.className,
				classMatch = " " + temp + " ";		
			for (var i = 0, j = classArray.length; i < j; i++) {
				if (classMatch.indexOf(" " + classArray[i] + " ") < 0) {
					temp += (temp ? " " : "") + classArray[i];
				}
			}	
			element.className = temp;
			return element;
		},
		/**
		*** @name removeClass
		***	@param {Object} element 节点对象, {String} className 类名
		*** @说明
				删除目标节点的class
		**/
		removeClass: function(element, className) {
			var oldClass = element.className.split(/\s+/),
				newClass = className.split(/\s+/);
			for (var i = 0, j = newClass.length; i < j; ++i){
				for(var x = 0, y = oldClass.length; x < y; ++x){
					if(oldClass[x] == newClass[i]){
						oldClass.splice(x, 1);
						break;
					}
				}
			}
			element.className = oldClass.join(' ');
			return element;
		},
		/**
		*** @name setStyle
		***	@param {Object} element 节点对象, {String} key 属性名, {Any} value 属性值
		*** @说明
				设置指定节点的style
		**/
		setStyle: function(element, key, value) {
			key = PF.string.camel(key);
			if (!PF.browser.ie) {
				if (key == "float") {
					key = "cssFloat";
				}
				element.style[key] = value;
			} else {
				switch(key) {
					case "opacity":
						element.style.filter = "alpha(opacity=" + (value * 100) + ")";			
						break;
					case "float":
						key = "styleFloat";
					default:
						element.style[key] = value;
				}
			}
		},
		/**
		*** @name getStyle
		***	@param {Object} element 节点对象, {String} key 属性名
		*** @说明
				获取指定节点的style
		**/
		getStyle: function(element, key) {
			key = PF.string.camel(key);
			if (!PF.browser.ie) {
				if (key == "float") {
					property = "cssFloat";
				}
				try {
					var comp = document.defaultView.getComputedStyle(element, "");
				} catch (e) {}
				return element.style[key] || (comp ? comp[key] : null) || null;
			} else {
				switch(key) {
					case "opacity":
						var temp = 100;
						try {
							temp = element.filters["DXImageTransform.Microsoft.Alpha"].opacity;
						} catch (e) {
							try {
								temp = element.filters("alpha").opacity;
							} catch (e) {}
						}
						return temp/100;
					case "float":
						key = "styleFloat";
					default:
						var value = element.currentStyle ? element.currentStyle[key] : null;
						return (element.style[key] || value);
				}
			}
		},
		/**
		*** @name getPosition
		***	@param {Object} element 节点对象
		*** @说明
				获取目标节点在文档中的位置
		**/
		getPosition: function(element) {
			var pos = {left: 0, right: 0},
				parent = null,
				box;
			try {
				box = element.getBoundingClientRect();
				var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
				var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
				pos = {left: box.left + scrollLeft, top: box.top + scrollTop};
				return pos;
			} catch(e) {
				try {
					box = document.getBoxObjectFor(element);
					var borderLeft = f.getStyle(element, 'borderLeftWidth') ? parseInt(f.getStyle(element, 'borderLeftWidth')) : 0;
					var borderTop = f.getStyle(element, 'borderTopWidth') ? parseInt(f.getStyle(element, 'borderTopWidth')) : 0;
					pos = {left: box.x-borderLeft, top: box.y - borderTop};
					return pos;
				} catch(e) {
					try {
						pos = {left: element.offsetLeft, top: element.offsetTop};
						parent = element.offsetParent;
						if (parent != element) {
							while(parent) {
								pos[left] += parent.offsetLeft;
								pos[top] += parent.offsetTop;
								parent = parent.offsetParent;
							}
						}
						if (PF.browser.opera || (PF.browser.safari && PF.dom.getStyle(element, 'position') == 'absolute')) {
							pos[left] -= document.body.offsetLeft;
							pos[top] -= document.body.offsetTop;
						}
						return pos;
					} catch (ex) {return pos;}
				}
			}
		
		}
	},
	cookie: { // cookie
		_isValidKey: function(key) {
			return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key);
		},
		/**
		*** @name setRaw
		***	@param {String} key 键名, {String} value 键值, {Object} options 其他选项
		*** @说明
				options的参数：
					path: cookie路径,
					expires: cookie过期事件, Number类型，单位为MS,
					domain: cookie域名,
					secure: cookie是否安全传输
				设置cookie值，不对值进行编码
		**/
		setRaw: function(key, value, options) {
			if (!this._isValidKey(key)) {
				return;
			}
			options = options || {};
			var expires = options.expires;
			if (typeof options.expires == "number") {
				expires = new Date();
				expires.setTime(expires.getTime() + options.expires);
			}
			document.cookie = 
				key + "=" + value
				+ (options.path ? "; path=" + options.path : "")
				+ (expires ? "; expires=" + expires.toGMTString() : "")
				+ (options.domain ? "; domain=" + options.domain : "")
				+ (options.secure ? "; secure" : "");
		},
		/**
		*** @name set
		***	@param {String} key 键名, {String} value 键值, {Object} 其他选项
		*** @说明
				其他看setRaw
				设置cookie值，用encodeURIComponent进行编码
		**/
		set: function(key, value, options) {
			this.setRaw(key, encodeURIComponent(value), options);
		},
		/**
		*** @name getRaw
		***	@param {String} key 键名
		*** @说明
				获取cookie的值，不对值进行解码
		**/
		getRaw: function(key) {
			if (this._isValidKey(key)) {
				var reg = new RegExp("(^| )" + key + "=([^;]*)(;|\x24)"),
					temp = reg.exec(document.cookie);
				if (temp) {
					return temp[2] || null;
				}	
			}
			return null;
		},
		/**
		*** @name get
		***	@param {String} key 键名
		*** @说明
				获取cookie的值，用decodeURIComponent进行解码
		**/
		get: function(key) {
			var value = this.getRaw(key);
			if (typeof value == "string") {
				return decodeURIComponent(value);
			}
			return null;
		},
		/**
		*** @name remove
		***	@param {String} key 键名, {Object} 其他选项
		*** @说明
				options, 需要删除的cookie对应的path domain等值
				删除cookie的值
		**/
		remove: function(key, options) {
			options = options || {};
			options.expires = new Date(0);
			this.setRaw(key, "", options);
		}
	},
	ajax: { // ajax
		/**
		*** @name request
		***	@param {String} url 请求地址, {Object} options 其他选项
		*** @说明
				ajax操作核心方法
				options的参数：
				data: 请求的数据,
				method: 请求方式,
				headers: 自定义头部,
				username: 验证用户名,
				password: 验证密码,
				type: 返回数据,
				async: 是否异步调用,
				onstart: 在发送请求前调用执行函数,
				onsuccess: 在远程返回成功时执行函数,
				onfailure: 在远程返回失败时执行函数		
		**/
		request: function(url, options) {
			var xhr,
				_options = { // 默认选项
					data: null,
					method: "GET",
					headers: {},
					username: "",
					password: "",
					type: "text",
					async: true,
					onstart: function() {},
					onsuccess: function() {},
					onfailure: function() {}
				};
			_options = PF.extend(_options, options || {});
			var _getxhr = function() { // 创建xmlhttprequest对象
				if (window.XMLHttpRequest) {
					return new XMLHttpRequest();
				}
				if (window.ActiveXObject) {
					try {
						return new ActiveXObject("Msxml2.XMLHTTP");
					} catch (e) {
						try {
							return new ActiveXObject("Microsoft.XMLHTTP");
						} catch (e) {}
					}
				}
				return null;
			};
			var _onStateChange = function(success, failure) { // 状态执行
				if (this.readyState == 4) { // this === xhr
					if (this.status >= 200 && this.status < 300 || this.status == 304 || this.status == 1223) {
						var temp = "";
						try {
							if (_options.type == "xml") {
								temp = this.responseXML;
							} else {
								temp = this.responseText;
							}
						} catch (e) {}
						// 执行成功回调函数
						success.call(this, temp);
					} else {
						// 执行失败回调函数，返回xmlhttprequest对象
						failure.call(this);
					}
				} else {}
			};
			try {
				xhr = _getxhr();
				_options.method = _options.method.toUpperCase() == "GET" ? "GET" : "POST";
				if (_options.method == "GET") {
					if (_options.data) {
						url += (url.indexOf("?") >= 0 ? "&" : "?") + _options.data;
					}
				}
				xhr.onreadystatechange = function() {
					_onStateChange.call(xhr, _options.onsuccess || function() {}, _options.onfailure || function() {});
				};
				
				xhr.open(_options.method, url, _options.async, _options.username, _options.password);
				if (_options.method == "POST") {
					xhr.setRequestHeader("Content-Type",
						(_options.headers["Content-Type"] || "application/x-www-form-urlencoded"));
				}
				for (key in _options.headers) { // 遍历自定义头部定义，写入请求头部中
					if (_options.headers.hasOwnProperty(key)) {
						xhr.setRequestHeader(key, _options.headers[key]);
					}
				}
				_options.onstart && _options.onstart.call(xhr); // 发送请求前，执行回调函数
				xhr.send(_options.data); // 发送请求
				return xhr;
			} catch (e) {}
		},
		/**
		*** @name get
		***	@param {String} url 请求地址, {String} data 发送数据, {Function} onsuccess 回调函数
		*** @说明
				封装了get方法
		**/
		get: function (url, data, onsuccess) {
			PF.ajax.request(url, {
				data: data,
				onsuccess: onsuccess
			});
		},
		/**
		*** @name post
		***	@param {String} url 请求地址, {String} data 发送数据, {Function} onsuccess 回调函数
		*** @说明
				封装了post方法
		**/
		post: function(url, data, onsuccess) {
			PF.ajax.request(url, {
				method: "POST",
				data: data,
				onsuccess: onsuccess
			});
		},
		/**
		*** @name xmlHeader
		***	@param {String} url 请求地址, {String} data 发送数据, {Function} onsuccess 回调函数
		*** @说明
				封装了头部请求为"X-Requested-With" = "XMLHttpRequest"的方法
		**/
		xmlHeader: function(url, options) {
			if (options) {
				var headers = options.headers;
				if (headers) {
					headers["X-Requested-With"] = "XMLHttpRequest";
				} else {
					options.headers = {"X-Requested-With": "XMLHttpRequest"};
				}
			} else {
				var options = {};
				options.headers = {"X-Requested-With": "XMLHttpRequest"};
			}
			PF.ajax.request(url, options);
		}
	}	
};


	
// 设定快捷方式	

// 选择器
window.$ = PF.selector.$; // $选择器，最全的选择器
window.$I = PF.selector.$I; // $I选择器， id选择器
window.$T = PF.selector.$T; // $T选择器， tagName选择器
window.$N = PF.selector.$N; // $N选择器， name选择器
window.$C = PF.selector.$C; // $C选择器， className选择器

// 遍历
window.$_each = PF.each;

// 扩展
window.$_extend = PF.extend;


// JSON
window.$_decode = PF.json.parse;
window.$_encode = PF.json.stringify;

// DOM
window.$_addClass = PF.dom.addClass;
window.$_removeClass = PF.dom.removeClass;
window.$_getAttr = PF.dom.getAttr;
window.$_setAttr = PF.dom.setAttr;
window.$_getStyle = PF.dom.getStyle;
window.$_setStyle = PF.dom.setStyle;
window.$_children = PF.dom.children;
window.$_remove = PF.dom.remove;
window.$_create = PF.dom.create;
window.$_insertBefore = PF.dom.insertBefore;
window.$_insertAfter = PF.dom.insertAfter;

// EVENT
window.$_addHandler = PF.event.addHandler;
window.$_addHandlers = PF.event.addHandlers;
window.$_removeHandler = PF.event.removeHandler;

// AJAX
window.$_ajax = PF.ajax.request;
window.$_ajaxXmlHeader = PF.ajax.xmlHeader;

